Nacteni textoveho souboru do string promenne

Otázka od: Martin Radvansky

14. 7. 2004 13:00

Dobry den,
  Narazil jsem na problem s dobu nacitani textoveho souboru
  
  Zde je ukazka kodu
  while not EOF(ltfFile) do begin
    Readln(ltfFile, lsRow);
    .
    .
    .
    lsText := lsText + lsRow + #13;
  end;

  Pokud nacitam textovy soubor timto zpusobem, soubor ma asi 3,5MB
  asi 33500 radku, tak doba, kterou na to potrebuje 3.2G P4 HT je
  kolem 120 sec (coz je katastroficke). Podle profileru je to zpusobeno tim
prirazovanim
  lsText := lsText + lsRow;

  pokud si testuju pouze lsText := lsRow + #13;
  tak je rychlost nekde na urovni setin sekundy.

  Existuje neco jako prirazeni "pripojenim" k retezci?

  Diky za radu.

--
S pozdravem,
 Martin Radvansky


Odpovedá: Fitz Ladislav

14. 7. 2004 14:30

ja si na to udelal object, neni to nic svetoborneho ale me to staci

pred nacitanim zavolas StartSet; a po nacitani EndSet ktery ti vrati nacteny
string

snad to pomuze

 tLongString = class
  private
   FString : string;
   FLength,
   FSize,
   FPosition : longint;
   procedure _Free;
  public
   constructor Create;
   destructor Destroy; override;
   property Length : longint read FLength;
   function StartTransaction : longint;
   procedure CancelTransaction (value : longint);
   procedure StartSet;
   function EndSet : string;
   procedure AddChar (ch : char);
   procedure AddLine;
   procedure AddText (const txt : string);
 end;

procedure tLongString._Free;
begin
  FString:='';
  FLength:=0;
  FSize:=0;
  FPosition:=0;
end;
constructor tLongString.Create;
begin
  inherited Create;
  _Free;
end;
destructor tLongString.Destroy;
begin
  _Free;
  inherited;
end;
function tLongString.StartTransaction : longint;
begin
  result:=FPosition;
end;
procedure tLongString.CancelTransaction (value : longint);
begin
  FPosition:=value;
  FLength:=value-1;
end;
procedure tLongString.StartSet;
begin
  FLength:=0;
  FSize:=$4000;
  FPosition:=1;
  SetLength (FString,FSize);
end;
function tLongString.EndSet : string;
begin
  result:=Copy (FString,1,FLength);
  _Free;
end;
procedure tLongString.AddChar (ch : char);
begin
  if (FPosition>=FSize) then
    begin
      inc (FSize,$4000);
      SetLength (FString,FSize);
    end;
  FString[FPosition]:=ch;
  inc (FPosition);
  inc (FLength);
end;
procedure tLongString.AddLine;
begin
  if (FPosition+1>=FSize) then
    begin
      inc (FSize,$4000);
      SetLength (FString,FSize);
    end;
  FString[FPosition]:=#13;
  inc (FPosition);
  FString[FPosition]:=#10;
  inc (FPosition);
  inc (FLength,2);
end;
procedure tLongString.AddText (const txt : string);
var l : longint;
begin
  l:=system.Length (txt);
  if (l>0) then
  begin
    if (FPosition+l>=FSize) then
      begin
        inc (FSize,$4000*(1+(l div $4000)));
        SetLength (FString,FSize);
      end;
    Move (txt[1],FString[FPosition],l);
    inc (FPosition,l);
    inc (FLength,l);
  end;
end;


Odpovedá: Daniel Frantik

14. 7. 2004 14:33

> -----Original Message-----
> Dobry den,
> Narazil jsem na problem s dobu nacitani textoveho souboru
> Zde je ukazka kodu
> while not EOF(ltfFile) do begin
> Readln(ltfFile, lsRow);
> lsText := lsText + lsRow + #13;
> end;
Ahoj,
  problem je v realokaci pameti pro ulozeni stringu lsText pri kazdem
prirazeni.
Reseni co me napadaji na prvni pohled:
  a) TStringList.LoadFromFile - 3,5MB by nemel byt problem ... nicmene
sekundy to asi budou
  b) Pouzit streamy
  c) alokovat pevny kus pameti a pak presunovat data

Danik


Odpovedá: Milan Tomes

14. 7. 2004 13:57

A proc s tim nepracujes jako se streamem ??? Jeste lepsi je
MemoryMappedFile. Podivej se do unity JclFileUtils na tridu
TJclMappedTextReader. Myslim, ze Ti hodne pomuze a hlavne cely proces
neskutecne zrychli. Pokud potrebujes nacist cely soubor do jednoho stringu,
tak se podivej na unitu JclStrings a funkci FileToString.

HTH

S pozdravem

Milan Tomes


> [mailto:delphi-l-owner@clexpert.cz]On Behalf Of Martin Radvansky
> Sent: Wednesday, July 14, 2004 1:22 PM
>
> Dobry den,
> Narazil jsem na problem s dobu nacitani textoveho souboru
> asi 33500 radku, tak doba, kterou na to potrebuje 3.2G P4 HT je
> kolem 120 sec (coz je katastroficke). Podle profileru je to
> Martin Radvansky


Odpovedá: Vaclav Sazima

14. 7. 2004 13:43

 Ahoj,
1. Zkusil bych jak dopadne TStringList.loadfromfile

nebo
S : TFileStream;
lsText : string;
...
   setlength (lsText,S.Size);
   S.ReadBuffer (isText [1],S.Size);
...

Martin Radvansky wrote:

> Narazil jsem na problem s dobu nacitani textoveho souboru


Odpovedá: Pavel Poles

14. 7. 2004 14:03

> Zde je ukazka kodu
> while not EOF(ltfFile) do begin
> Readln(ltfFile, lsRow);
> .
> .
> .
> lsText := lsText + lsRow + #13;
> end;

A co pomoci Tstringlist.LoadFromFile? Myslim ze by to melo byt rychlejsi,
a jako string to pak dostane pre TStringList.Text, nebo
TStringList.DelimitedText
to se prevadi pres Pchar takze je to rychle.

> Pokud nacitam textovy soubor timto zpusobem, soubor ma asi 3,5MB
> asi 33500 radku, tak doba, kterou na to potrebuje 3.2G P4 HT je
> kolem 120 sec (coz je katastroficke). Podle profileru je to zpusobeno
tim prirazovanim
> lsText := lsText + lsRow;

Scitani stringu strasne zpomaluje. Optimalizace je jedine pracovat s PChar a
ne se stringem.

Pavel Poles


Odpovedá: Petr Vones

14. 7. 2004 14:53

From: "Martin Radvansky" <delphiconf@radvansky.net>
> Existuje neco jako prirazeni "pripojenim" k retezci?

Samozrejme, alokovat retezec o velikosti souboru a do tohoto bufferu nahrat
data primo. Viz funkce FileToString v JCL: http://sourceforge.net/projects/jcl

Petr Vones


Odpovedá: Ludek Finstrle

14. 7. 2004 14:36

> Existuje neco jako prirazeni "pripojenim" k retezci?

Musel bys to udelat pres PChar a pak tam neco jako pripojeni nakonec je.
Ale PChar musis alokovat v pameti (coz by +- podle velikosti souboru
snad nemel byt az tak velky problem).

Luf


Odpovedá: Martin Radvansky

15. 7. 2004 7:03

Dobry den,

PV> Samozrejme, alokovat retezec o velikosti souboru a do tohoto bufferu nahrat
PV> data primo. Viz funkce FileToString v JCL:
PV> http://sourceforge.net/projects/jcl

Diky vsem za pomoc, pouzil jsem jcl FileToString. Rychlot nacteni je
prakticky okamzite.

--
S pozdravem,
 Martin Radvansky